package system

import (
	"context"
	"time"

	"portal/internal/common"
	"portal/internal/errorx"
	"portal/internal/svc"
	"portal/internal/tool/auth"
	"portal/internal/types"
	"portal/model"

	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
)

type EditRolePermLogic struct {
	logx.Logger
	ctx       context.Context
	svcCtx    *svc.ServiceContext
	menuModel model.SysMenuModel
	userModel model.SysUserModel
	roleModel model.SysRoleModel
}

func NewEditRolePermLogic(ctx context.Context, svcCtx *svc.ServiceContext) *EditRolePermLogic {
	return &EditRolePermLogic{
		Logger:    logx.WithContext(ctx),
		ctx:       ctx,
		svcCtx:    svcCtx,
		menuModel: model.NewSysMenuModel(svcCtx.Orm),
		userModel: model.NewSysUserModel(svcCtx.Orm),
		roleModel: model.NewSysRoleModel(svcCtx.Orm),
	}
}

func (l *EditRolePermLogic) EditRolePerm(req *types.EditRolePermRequest) (resp *types.CommonResponse, err error) {
	// todo: add your logic here and delete this line
	err = auth.HasPermission(l.menuModel, l.ctx, "system:role:edit")
	if err != nil {
		return nil, errorx.Unauthorized
	}
	authinfo, err := auth.GetAuth(l.ctx)
	if err != nil {
		return nil, errorx.AuthNoFound
	}
	if isAdmin,_ := auth.IsAdmin(l.ctx); !isAdmin {
		err = l.userModel.ExistByRidUid(l.ctx, nil, req.RoleId, authinfo.UserId)
		if err != nil {
			return nil, errorx.SqlExistError
		}
	}

	roledto, err := l.roleModel.FindOne(l.ctx, req.RoleId)
	if err != nil {
		return nil, errorx.SqlSearchError
	}

	if len(req.RoleName) > 0 {
		roledto.RoleName = req.RoleName
	}
	if len(req.RoleKey) > 0 {
		roledto.RoleKey = req.RoleKey
	}
	if req.RoleSort > 0 {
		roledto.RoleSort = req.RoleSort
	}
	if len(req.DataScope) > 0 {
		roledto.DataScope = req.DataScope
	}
	if len(req.Status) > 0 {
		roledto.Status = req.Status
	}

	oprRoleRelations(l.roleModel, l.ctx, req.RoleId, req.DeptIds, req.MenuIds, common.OPR_UPDATE)

	roledto.UpdateTime = time.Now().Unix()
	roledto.UpdateBy = authinfo.UserName
	err = l.roleModel.Edit(l.ctx, nil, roledto)
	return &types.CommonResponse{
		Status: 200,
		Msg:    "更新成功",
	}, err
}

func oprRoleRelations(roleModel model.SysRoleModel, ctx context.Context, roleId int64, deptIds, menuIds []*int64, opr string) error {
	isOprRD, isOprRM := false, false
	if deptIds != nil {
		isOprRD = true
	}
	if menuIds != nil {
		isOprRM = true
	}

	if isOprRD {
		delRDs := make([]*int64, 0)
		addRDs := make([]*int64, 0)
		if opr == common.OPR_INSERT {
			err := roleModel.AddRoleDepts(ctx, nil, roleId, deptIds)
			if err != nil {
				return err
			}
		} else if opr == common.OPR_UPDATE {
			// 修改用户对角色以及用户对岗位的映射
			rds, err := roleModel.ListRoleDepts(ctx, nil, roleId)
			if err != nil && err != sqlx.ErrNotFound{
				return err
			}
			for _, fval := range deptIds {
				isHas := false
				for _, sval := range rds {
					if sval.DeptId == *fval {
						isHas = true
						break
					}
				}
				if !isHas {
					addRDs = append(addRDs, fval)
				}
			}
			for _, fval := range rds {
				isHas := false
				for _, sval := range deptIds {
					if *sval == fval.DeptId {
						isHas = true
						break
					}
				}
				if !isHas {
					delRDs = append(delRDs, &fval.DeptId)
				}
			}
			if len(addRDs) > 0 {
				err = roleModel.AddRoleDepts(ctx, nil, roleId, addRDs)
				if err != nil {
					return err
				}
			}
			if len(delRDs) > 0 {
				err = roleModel.DelRoleDepts(ctx, nil, roleId, delRDs)
				if err != nil {
					return err
				}
			}
		}
	}
	if isOprRM {
		delRMs := make([]*int64, 0)
		addRMs := make([]*int64, 0)
		if opr == "insert" {
			err := roleModel.AddRoleMenus(ctx, nil, roleId, menuIds)
			if err != nil {
				return err
			}
		} else if opr == "update" {
			// 修改用户对角色以及用户对岗位的映射
			rms, err := roleModel.ListRoleMenus(ctx, nil, roleId)
			if err != nil && err != sqlx.ErrNotFound{
				return err
			}
			for _, fval := range menuIds {
				isHas := false
				for _, sval := range rms {
					if sval.MenuId == *fval {
						isHas = true
						break
					}
				}
				if !isHas {
					addRMs = append(addRMs, fval)
				}
			}
			for _, fval := range rms {
				isHas := false
				for _, sval := range menuIds {
					if *sval == fval.MenuId {
						isHas = true
						break
					}
				}
				if !isHas {
					delRMs = append(delRMs, &fval.MenuId)
				}
			}
			if len(addRMs) > 0 {
				err = roleModel.AddRoleMenus(ctx, nil, roleId, addRMs)
				if err != nil {
					return err
				}
			}
			if len(delRMs) > 0 {
				err = roleModel.DelRoleMenus(ctx, nil, roleId, delRMs)
				if err != nil {
					return err
				}
			}
		}
	}
	return nil
}
